home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
program
/
szadb1_4.zoo
/
src
/
stepping.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-11-13
|
17KB
|
621 lines
/* Copyright (c) 1990 by Sozobon, Limited. Authors: Anthony Howe,
* Michal Jaegermann
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*
* Source code in this file consist of additons and modifications
* to an original szadb code by Johann Ruegg and Don Dugger and is
* an integral part of expanded version of szadb debugger.
*
* stepping.c 68000 Trace & Break Point Functions
* 23 Mar 90 ACH
* 1 Apr 90 MJ
* added temporary breakpoints
* separated next and jump accross branch
* added new instructions to skip
* added counts on breakpoints
* changed way in which return address is found
* set hooks for executing instructions on
* breakpoints
* 13 Nov 90 MJ
* modified code which searches for a function
* return address in order to marry an original
* method from prstack and ACH heuristic approach
*/
#include <stddef.h>
#include <setjmp.h>
#include "adb.h"
#define IN_STEPPING
#include "lang.h"
extern long bcount;
extern int lastc;
extern int lb_cur, lb_fill;
extern jmp_buf cont_buf;
#define BPT 0x4afc /* illegal op */
#define BP_VALID 1
#define BP_ACTIVE 2
/*** not used
#define JSR 0047200
#define JMP 0047300
** #define EA_MASK 0177700 ***//* mask out effective address */
typedef struct {
short *addr;
short instr;
union {
char *tmp_cmd[3];
struct {
long count;
long o_cnt;
char *cmdline;
} user;
} request;
int flag;
} break_point;
/* various storage for stepping commands */
static char bpstat[3] = {SILENT, SILENT, ON};
static char stp_req[3][LINESZ + 2];
static char findcmds[] = "=\"returns \";<d0=Xrr;<d0=p\n";
int print_regs;
/*
* The first position on the following list is used only for temporary
* breakpoints and is not available to a user.
*/
/*
* Initialize explicitely T_BPT - other are set to 0 by default.
* This union initialization is NOT portable, but Sozobon C accepts it.
*/
static break_point bpt_list[MAXBPTS + 1] = {
{(short *) 0, (short) 0, stp_req[0], stp_req[1], findcmds, 0}
};
#define T_BPT bpt_list[0]
extern char **bpt_cmds;
static break_point *
free_bpt (addr)
short *addr;
/*
* Find a free slot on a list of user breakpoints
*/
{
break_point *bp = &bpt_list[1];
break_point *last = &bpt_list[MAXBPTS + 1];
for (; bp < last; bp++)
if ((bp->flag & BP_VALID) == 0 || bp->addr == addr)
return (bp);
return (NULL);
} /* free_bpt */
static break_point *
find_bpt (addr)
short *addr;
/*
* Find if a user breakpoint is set at a given address
*/
{
break_point *bp = &bpt_list[1];
break_point *last = &bpt_list[MAXBPTS + 1];
for (; bp < last; bp++)
if (bp->flag & BP_VALID && bp->addr == addr)
return (bp);
return (NULL);
} /* find_bpt */
static char *
find_bcmd (bp, kind)
break_point *bp;
int kind;
/*
* Return an address of a buffer with commands which should be
* executed for a given breakpoint or NULL
*/
{
char *cmds;
int stat;
if (CM_CONT == kind) {
if (NULL != (cmds = bp->request.user.cmdline)) {
if (ON != *cmds++)
cmds = NULL;
}
}
else { /* temporary breakpoint set by a stepping
* command */
cmds = NULL;
if (SILENT != (stat = bpstat[--kind])) {
for (;;) {
if (ON == stat || (0 == kind && SILENT != stat)) {
cmds = T_BPT.request.tmp_cmd[kind];
break;
}
if (0 == kind)
break;
stat = bpstat[--kind];
}
}
}
return (cmds);
}
static void
exec_break (bp, kind)
break_point *bp;
int kind;
/*
* Execute commands associated with a given breakpoint
*/
{
extern registers regs[];
extern long dot;
if (CM_CONT == kind) {
if (NULL != bp) {
if (bp->request.user.count) {
--(bp->request.user.count);
longjmp (cont_buf, 1);
}
else {
bp->request.user.count = bp->request.user.o_cnt;
dot = (long) bp->addr;
src_line (find_bcmd (bp, kind));
prtf (BREAK_AT, bp->addr);
}
}
}
else { /* CM_STEP, CM_NEXT, CM_FINISH */
dot = *regs[PC].value;
src_line (find_bcmd ((break_point *) NULL, kind));
}
if (print_regs)
prregs ();
prbpt (dot = *regs[PC].value);
putchr ('\n');
return;
}
static void
check_break (kind)
int kind;
/*
* Kind indicates which stepping command caused break.
* Not used for traps of other kind.
*/
{
extern int lasttrap;
extern registers regs[];
extern char *tnm[];
void exec_break ();
switch (lasttrap) {
case 2:
case 3: /* bus & address errors */
prbuserr ();
break;
case 9:
exec_break (&T_BPT, kind);
break; /* trace */
case 10:
prt (PROCESS_EXIT);
seeerr ();
exit (0);
case 4: /* illegal instruction -- breakpoint */
/*
* Give priority to temporary breakpoints set by stepping commands.
* One may reprocess if first condition fires but we are going to
* miss breakpoint anyway if walked through by :n(ext) which reverted
* to :s(tep), so let be consistent.
*/
if ((T_BPT.flag & BP_VALID) &&
(T_BPT.addr == (short *) (*regs[PC].value))) {
exec_break (&T_BPT, kind);
}
else {
exec_break (find_bpt ((short *) (*regs[PC].value)), kind);
} /* if */
break;
default:
prtf ("trap: %s\n", tnm[lasttrap]);
} /* switch */
} /* check_break */
static void
bpts_on ()
/*
* Turn on all the break points, user and temporary,
* before full speed execution. First go through user
* breakpoints. If T_BPT is on the same location as
* a user breakpoint, then the second breakpoint turned
* on will get BPT (invalid) instruction stored in it.
* Turn off in a reverse order!
*/
{
int i = MAXBPTS;
break_point *bp = &bpt_list[1];
extern long getn ();
for (;;) {
if (bp->flag & BP_VALID) {
bp->flag |= BP_ACTIVE;
bp->instr = (short) getn (bp->addr, 2);
putn ((long) BPT, bp->addr, 2);
} /* if */
if (bp == &T_BPT)
break;
if (--i)
bp++;
else
bp = &T_BPT;
} /* for */
} /* bpts_on */
static void
bpts_off ()
/*
* Turn off all the break points after full speed execution.
* This restores the instructions so that they can be viewed normally.
* Temporary breakpoint has to be turned off before user breakpoints.
* Ordering is critical - otherwise you may got BPT (invalid)
* instructions sprinkled over your code
*/
{
break_point *bp = &bpt_list[0];
break_point *last = &bpt_list[MAXBPTS + 1];
do {
if (bp->flag & BP_ACTIVE) {
bp->flag &= ~BP_ACTIVE;
putn ((long) bp->instr, bp->addr, 2);
} /* if */
bp++;
} while (bp < last);
} /* bpts_off */
int
MakeReq (kind)
short kind;
/*
* Handle request line for stepping commands.
* Return 0 if there was no requests on a command line and non-zero otherwise.
*/
{
int idx = kind - 1;
int status;
extern int getrequs ();
if (BLANK == (status = getrequs (stp_req[idx]))) {
return 0;
}
if (REVERT == status) {
if (CM_FINISH != kind) {
status